#include "StdAfx.h"
#include "DirectShowPlayer.h"
#include <d3d9.h>
#include <Vmr9.h>
#include "DDrawH264Play.h"
#ifdef SUPPORT_H264
#include "DecodeFilter.h"
#endif

const UINT DEFAULT_FPS = 25;

template <typename T>
void SafeRelease(T *&ptr)
{
	if (ptr != NULL)
	{
		ptr->Release();
		ptr = NULL;
	}
}


//--------------------DirectShowPlayer CLASS IMPLEMENT--------------------------

DirectShowPlayer::DirectShowPlayer(void)
	:_fps(DEFAULT_FPS),
	_format(0),
	_width(0),
	_height(0),
	_destHeight(0),
	_destWidth(0),
	_parentWindow(NULL),
	_x(0),
	_y(0),
	_outputHeight(0),
	_outputWidth(0),
	_isCreated(false),
	_playerType(PLAYERTYPE_WINDOWS_MEDIA_FILE),
	_dataProvider(NULL),
	_param(0)
{
}

DirectShowPlayer::~DirectShowPlayer(void)
{
	DestroyPlayer();
}

int DirectShowPlayer::Start()
{
	if (!_isCreated)
		return -1;

	if (_playerType == PLAYERTYPE_WINDOWS_MEDIA_FILE)
	{
		CComQIPtr<IMediaControl> mediaControl(_graphBuilder);
		if (mediaControl == NULL)
			return -2;

		HRESULT hr;
		return SUCCEEDED(hr = mediaControl->Run()) ? 0 : -2;
	}
	else
	{
		return _h264Play->StartPlay();
	}
}

void DirectShowPlayer::Stop()
{
	if (!_isCreated)
		return;

	if (_playerType == PLAYERTYPE_WINDOWS_MEDIA_FILE)
	{
		CComQIPtr<IMediaControl> mediaControl(_graphBuilder);
		if (mediaControl == NULL)
			return;

		mediaControl->Stop();
	}
	else
	{
		_h264Play->StopPlay();//_h264Play->StartPlay();
	}
}

void DirectShowPlayer::Pause()
{
	if (!_isCreated)
		return;

	if (_playerType != PLAYERTYPE_WINDOWS_MEDIA_FILE)
	{
		CComQIPtr<IMediaControl> mediaControl(_graphBuilder);
		if (mediaControl == NULL)
			return;

		mediaControl->Pause();
	}
	else
	{
		_h264Play->PausePlay();
	}
}

int DirectShowPlayer::DisableAllCallback()
{
	if (!_isCreated)
		return -1;

	if (_playerType != PLAYERTYPE_H264_BIT_STREAM 
		&& _playerType != PLAYERTYPE_RAW_FRAME_STREAM)
	{
		return -1;
	}

	_h264Play->SetDataProvider(m_session, NULL, NULL);
	_h264Play->SetDecodeCallback(m_session, NULL, NULL, true);
	_h264Play->SetDrawCallback(m_session, NULL, NULL);

	return 0;
}

int DirectShowPlayer::SnapShot(const char *filename)
{
	if (!_isCreated)
		return -1;

	if (filename == NULL)
		return -1;

	FILE *file = fopen(filename, "wb");
	if (file == NULL)
		return -1;

	long bufSize = 1920 * 1080 * 4 + 10240;
	BYTE *imageBuf = NULL;
	imageBuf = new BYTE[bufSize];

	if (GetSnapShot((char *) imageBuf, bufSize) < 0)
	{
		delete[] imageBuf;
		fclose(file);
		DeleteFile(filename);

		return -1;
	}

	LPBITMAPINFOHEADER bmpHeader = (LPBITMAPINFOHEADER) imageBuf;
	bufSize = sizeof(BITMAPINFOHEADER) + GetBitmapSize(bmpHeader);

	BITMAPFILEHEADER fileHeader;
	memset(&fileHeader, 0, sizeof(fileHeader));
	fileHeader.bfType = 'MB'; //file type is "BM"
	fileHeader.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + bufSize); 	
	fileHeader.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + bmpHeader->biSize + bmpHeader->biClrUsed * sizeof (RGBQUAD); 

	fwrite(&fileHeader, 1, sizeof(fileHeader), file);
	fwrite(imageBuf, 1, bufSize, file);

	delete[] imageBuf;
	fclose(file);

	return 0;
}

int DirectShowPlayer::GetSnapShot(char *buf, UINT bufSize)
{
	if (!_isCreated || buf == NULL || bufSize < sizeof(BITMAPFILEHEADER))
		return -1;

	if (_h264Play.get() != NULL)
		return _h264Play->Snapshot(buf, bufSize);

	HRESULT hr;
	BYTE *ptr = NULL;
	LPBITMAPINFOHEADER bmpHdr = NULL;

	CComQIPtr<IVMRWindowlessControl> windowlessControl(_vmr9);
	if (windowlessControl != NULL)
	{
		hr = windowlessControl->GetCurrentImage(&ptr);
		if (FAILED(hr))
			return -1;

		bmpHdr = (LPBITMAPINFOHEADER) ptr;
		memcpy(buf, ptr, sizeof(BITMAPINFOHEADER) + GetBitmapSize(bmpHdr));

		CoTaskMemFree(ptr);
	}	
	else
	{
		CComQIPtr<IVMRWindowlessControl9> windowlessControl9(_vmr9);
		if (windowlessControl9 != NULL)
		{
			hr = windowlessControl9->GetCurrentImage(&ptr);
			if (FAILED(hr))
				return -1;

			bmpHdr = (LPBITMAPINFOHEADER) ptr;
			memcpy(buf, ptr, GetBitmapSize(bmpHdr));

			CoTaskMemFree(ptr);
		}
		else
		{
			CComQIPtr<IBasicVideo> basicVideo(_vmr9);
			if (basicVideo == NULL)
				return -1;

			long minBufSize = 0;

			hr = basicVideo->GetCurrentImage(&minBufSize, NULL);
			if (FAILED(hr) || (long) bufSize < minBufSize)
				return -1;

			long actualBufSize = bufSize;
			hr = basicVideo->GetCurrentImage(&actualBufSize, (long *) buf);
			if (FAILED(hr))
				return -1;
		}
	}

	return 0;
}

int DirectShowPlayer::GetSnapShotSize()
{
	if (!_isCreated)
		return -1;

	if (_h264Play.get() != NULL)
		return _h264Play->GetSnapshotSize();

	long bufSize = 0;
	HRESULT hr;
	BYTE *ptr = NULL;
	LPBITMAPINFOHEADER bmpHdr = NULL;

	CComQIPtr<IVMRWindowlessControl> windowlessControl(_vmr9);
	if (windowlessControl != NULL)
	{
		hr = windowlessControl->GetCurrentImage(&ptr);
		if (FAILED(hr))
			return -1;

		bmpHdr = (LPBITMAPINFOHEADER) ptr;
		bufSize = GetBitmapSize(bmpHdr) + sizeof(BITMAPINFOHEADER);
		if (bmpHdr->biBitCount <= 8)
			bufSize += 4 * (1 << bmpHdr->biBitCount);

		CoTaskMemFree(ptr);
	}	
	else
	{
		CComQIPtr<IVMRWindowlessControl9> windowlessControl9(_vmr9);
		if (windowlessControl9 != NULL)
		{
			hr = windowlessControl9->GetCurrentImage(&ptr);
			if (FAILED(hr))
				return -1;

			bmpHdr = (LPBITMAPINFOHEADER) ptr;
			bufSize = GetBitmapSize(bmpHdr) + sizeof(BITMAPINFOHEADER);
			if (bmpHdr->biBitCount <= 8)
				bufSize += 4 * (1 << bmpHdr->biBitCount);

			CoTaskMemFree(ptr);
		}
		else
		{
			CComQIPtr<IBasicVideo> basicVideo(_vmr9);
			if (basicVideo == NULL)
				return -1;

			hr = basicVideo->GetCurrentImage(&bufSize, NULL);
			if (FAILED(hr))
				return -1;
		}
	}

	return bufSize;
}

int DirectShowPlayer::UpdateVideoWindow()
{
	
	if (!_isCreated)
	{
		return -1;
	}
		
	
	if (_playerType == PLAYERTYPE_WINDOWS_MEDIA_FILE)
		UpdateOutputPosition();
	else
		_h264Play->UpdateVideoWindowRect();
	
	

	return 0;


}

int DirectShowPlayer::GetPlaybackBitrate()
{
	if (!_isCreated)
		return -1;

	if (_playerType == PLAYERTYPE_WINDOWS_MEDIA_FILE)
		return _h264DecodeFilter->GetBitrate();
	else
		return _h264Play->GetBitrate();

	return -1;
}

int DirectShowPlayer::GetTotalFrame()
{
	if (!_isCreated)
		return -1;

	return 0;
}

int DirectShowPlayer::GetActualFps()
{
	if (!_isCreated)
		return -1;

	if (_playerType == PLAYERTYPE_WINDOWS_MEDIA_FILE)
		return _h264DecodeFilter->GetActualFps();
	else
		return _h264Play->GetActualFps();

	/*
	long width, height;
	HRESULT hr = basicVideo->GetVideoSize(&width, &height);
	if (SUCCEEDED(hr))
	{
		if (height == 480 || height == 240)
			return 30;
		else 
			return 25;
	}
	else
		return 0;
	*/
}

int DirectShowPlayer::SetDisplayRect(const RECT &rect)
{
	if (!_isCreated)
		return -1;

	CComQIPtr<IBasicVideo> basicVideo(_vmr9);
	if (basicVideo == NULL)
		return -1;

	HRESULT hr;
	if (rect.left == 0 && rect.top == 0 && rect.right == 0 && rect.bottom == 0)
	{
		long width, height;
		basicVideo->GetVideoSize(&width, &height);
		hr = basicVideo->SetSourcePosition(0, 0, width, height);
	}
	else
	{
		hr = basicVideo->SetSourcePosition(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
	}

	return SUCCEEDED(hr) ? 0 : -1;
}


#ifdef SUPPORT_H264
int DirectShowPlayer::CreateWindowsMediaPlayer(const char *sourceName)
{
	if (_isCreated)
		return -1;

	_playerType = PLAYERTYPE_WINDOWS_MEDIA_FILE;
	_sourceName = sourceName;

	return InitializePlayer();
}

int DirectShowPlayer::CreateH264FileStreamPlayer(const char *sourceName, UINT fps)
{
	if (_isCreated)
		return -1;

	_playerType = PLAYERTYPE_H264_FILE_STREAM;
	_sourceName = sourceName;
	_fps = fps;

	return InitializePlayer();
}

int DirectShowPlayer::CreateH264StreamPlayer(PLAYBACKSESSION session, DataProviderCallBack dataProvider, UINT fps, LPVOID param, UINT width, UINT height)
{
	if (_isCreated)
		return -1;

	_playerType = PLAYERTYPE_H264_BIT_STREAM;
	_dataProvider = dataProvider;
	_fps = fps;
	m_session = session;
	_width = width;
	_height = height;
	_param = param;

	return InitializePlayer();
}
#endif

int DirectShowPlayer::CreateRawStreamPlayer(PLAYBACKSESSION session, DataProviderCallBack dataProvider, UINT fps, LPVOID param, UINT width, UINT height)
{
	if (_isCreated)
		return -1;

	_playerType = PLAYERTYPE_RAW_FRAME_STREAM;
	_dataProvider = dataProvider;
	_fps = fps;
	m_session = session;
	_width = width;
	_height = height;
	_param = param;

	return InitializePlayer();
}


void DirectShowPlayer::SetOutputPosition(HWND hwnd, int x, int y, int width, int height)
{
	_parentWindow = hwnd;
	_x = x;
	_y = y;
	_outputWidth = width;
	_outputHeight = height;

	UpdateOutputPosition();
}

void DirectShowPlayer::UpdateOutputPosition()
{
	if (!_isCreated)
	{
		
		return;
	}
		

	if (_h264Play.get() != NULL)
		_h264Play->SetOutputWindow(_parentWindow);

	if (_parentWindow == NULL || _playerType != PLAYERTYPE_WINDOWS_MEDIA_FILE)
	{
        return;
	}

	RECT srcPos, dstPos;
	CComQIPtr<IVMRWindowlessControl> windowlessControl(_vmr9);
	if (windowlessControl != NULL)
	{
		windowlessControl->SetVideoClippingWindow(_parentWindow);
		windowlessControl->GetVideoPosition(&srcPos, &dstPos);
		dstPos.left = _x;
		dstPos.top = _y;
		dstPos.right = _x + _outputWidth;
		dstPos.bottom = _y + _outputHeight;
		windowlessControl->SetVideoPosition(&srcPos, &dstPos);
//		BringWindowToTop(_parentWindow);
		HDC hdc = GetDC(_parentWindow);
		windowlessControl->RepaintVideo(_parentWindow, hdc);
		ReleaseDC(_parentWindow, hdc);
	}	
	else
	{
		CComQIPtr<IVMRWindowlessControl9> windowlessControl9(_vmr9);
		if (windowlessControl9 != NULL)
		{
			windowlessControl9->SetVideoClippingWindow(_parentWindow);
			windowlessControl9->GetVideoPosition(&srcPos, &dstPos);
			dstPos.left = _x;
			dstPos.top = _y;
			dstPos.right = _x + _outputWidth;
			dstPos.bottom = _y + _outputHeight;
			windowlessControl9->SetVideoPosition(&srcPos, &dstPos);
			BringWindowToTop(_parentWindow);
			HDC hdc = GetDC(_parentWindow);
			windowlessControl9->RepaintVideo(_parentWindow, hdc);
			ReleaseDC(_parentWindow, hdc);
		}
		else
		{
			CComQIPtr<IVideoWindow> videoWindow(_graphBuilder);
			if (videoWindow == NULL)
				return;

			videoWindow->put_AutoShow(OATRUE);
			videoWindow->put_Owner((OAHWND) _parentWindow);
			videoWindow->put_WindowStyle((_parentWindow != NULL) ? WS_CHILD : WS_OVERLAPPEDWINDOW);
			videoWindow->SetWindowPosition(_x, _y, _outputWidth, _outputHeight);
			videoWindow->put_MessageDrain((OAHWND) _parentWindow);
			videoWindow->put_Visible(TRUE);
		}
	}
   
	return;
}

void DirectShowPlayer::ChangeVolume(UINT volume)
{
	if (!_isCreated)
		return;

	if (_playerType == PLAYERTYPE_WINDOWS_MEDIA_FILE)
	{
		CComQIPtr<IBasicAudio> audio(_graphBuilder);
		if (audio != NULL)
			audio->put_Volume((volume - 100) * 100);
	}
}


bool DirectShowPlayer::HasAudio()
{
	if (!_isCreated)
		return false;

	if (_playerType == PLAYERTYPE_WINDOWS_MEDIA_FILE)
	{
		CComQIPtr<IBasicAudio> audio(_graphBuilder);
		return (audio != NULL);
	}
	else
	{
		return false;
	}
}

const LONGLONG UNIT = 10000;
bool DirectShowPlayer::Seek(DWORD position)
{
	if (!_isCreated)
		return false;

	if (_playerType == PLAYERTYPE_WINDOWS_MEDIA_FILE)
	{
		CComQIPtr<IMediaSeeking> mediaSeeking(_graphBuilder);
		if (mediaSeeking == NULL)
			return false;

		//mediaSeeking->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
		//bool needPause = false;
		//if (_playerType == PLAYERTYPE_WINDOWS_MEDIA_FILE && _h264DecodeFilter->IsPaused())
		//{
		//	needPause = true;
		//	_h264DecodeFilter->ContinuePlayback();
		//}

		LONGLONG current = LONGLONG(position) * UNIT;
		bool success = SUCCEEDED(mediaSeeking->SetPositions(
			&current, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame , 
			NULL, AM_SEEKING_NoPositioning));

		//Sleep(100);

		//if (needPause)
		//	_h264DecodeFilter->PausePlayback();

		return success;
	}
	else
	{
		return false;
	}
}

bool DirectShowPlayer::IsPlaying()
{
	if (!_isCreated)
		return false;

	if (_playerType == PLAYERTYPE_WINDOWS_MEDIA_FILE)
	{
		CComQIPtr<IMediaControl> mediaControl(_graphBuilder);
		if (mediaControl == NULL)
			return false;

		OAFilterState state;
		return SUCCEEDED(mediaControl->GetState(100, &state)) ? (state == State_Running) : false;
	}
	else
	{
		return true;
	}
}

bool DirectShowPlayer::GetVideoSize(int *width, int *height)
{
	if (!_isCreated)
		return false;

	if (_playerType == PLAYERTYPE_WINDOWS_MEDIA_FILE)
	{
		CComQIPtr<IBasicVideo> video(_graphBuilder);
		if (video == NULL)
			return false;

		return SUCCEEDED(video->GetVideoSize((long *) width, (long *) height));
	}
	else
	{
		return (_h264Play->GetActualVideoSize(*width, *height) == 0);
	}
}

int DirectShowPlayer::GetActualVideoSize(int *width, int *height)
{
	if (!_isCreated)
		return -1;

	// TODO:support other player types
	if (_playerType == PLAYERTYPE_H264_BIT_STREAM)
		return _h264Play->GetActualVideoSize(*width, *height);

	return -1;
}

int DirectShowPlayer::SetDrawCallback(DRAWCALLBACK drawCallback, long param)
{
	if (!_isCreated)
		return -1;

	// TODO:support other player types
	if (_playerType == PLAYERTYPE_H264_BIT_STREAM || _playerType == PLAYERTYPE_RAW_FRAME_STREAM)
		return _h264Play->SetDrawCallback(m_session, drawCallback, param);

	return -1;
}

int DirectShowPlayer::SetDecodeCallback(DECODECALLBACK decodeCallback, long param, bool needDisplay)
{
	if (!_isCreated)
		return -1;

	// TODO:support other player types
	if (_playerType == PLAYERTYPE_H264_BIT_STREAM)
		return _h264Play->SetDecodeCallback(m_session, decodeCallback, param, needDisplay);

	return -1;
}
// int DirectShowPlayer::SetFrameCallback(FrameCALLBACK callback, long param)
// {
// 	if (!_isCreated)
// 		return -1;
// 
// 	// TODO:support other player types
// 	if (_playerType == PLAYERTYPE_H264_BIT_STREAM)
// 		return _h264Play->SetFrameCallback(m_session, callback, param);
// 
// 	return -1;
// }
int DirectShowPlayer::ChangePlaybackFps(UINT fps)
{
	if (!_isCreated)
		return -1;

	// TODO:support other player types
	if (_playerType == PLAYERTYPE_H264_BIT_STREAM)
		return _h264Play->ChangePlaybackFps(fps);

	return -1;
}

int DirectShowPlayer::SetPlaybackRate(double rate)
{
	if (!_isCreated)
		return -1;

	if (_playerType == PLAYERTYPE_WINDOWS_MEDIA_FILE)
	{
		//CComQIPtr<IMediaSeeking> mediaSeeking(_graphBuilder);
		//if (mediaSeeking == NULL)
		//	return -1;

		//LONGLONG current, stoptime;
		//HRESULT hr = mediaSeeking->GetPositions(&current, &stoptime);
		//= LONGLONG(position) * UNIT;
		//bool success = SUCCEEDED(mediaSeeking->SetPositions(
		//	&current, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame , 
		//	NULL, AM_SEEKING_NoPositioning));

		_clock.SetRate(rate);
		return 0;
	}

	return -1;
}

int DirectShowPlayer::GetFilePlayTime(DWORD *milliseconds)
{
	if (!_isCreated)
		return -1;

	if (_playerType != PLAYERTYPE_WINDOWS_MEDIA_FILE)
		return -1;

	CComQIPtr<IMediaSeeking> mediaSeeking(_graphBuilder);
	if (mediaSeeking == NULL)
		return -1;

	LONGLONG duration;
	HRESULT hr = mediaSeeking->GetDuration(&duration);
	if (hr != S_OK)
		return -1;

	*milliseconds = static_cast<DWORD>(duration / UNIT);

	return 0;
}

int DirectShowPlayer::GetFileCurrTime(DWORD *milliseconds)
{
	if (!_isCreated)
		return -1;

	if (_playerType != PLAYERTYPE_WINDOWS_MEDIA_FILE)
		return -1;

	CComQIPtr<IMediaSeeking> mediaSeeking(_graphBuilder);
	if (mediaSeeking == NULL)
		return -1;

	LONGLONG current;
	HRESULT hr = mediaSeeking->GetCurrentPosition(&current);
	if (hr != S_OK)
		return -1;

	*milliseconds = static_cast<DWORD>(current / UNIT);

	return 0;
}

int DirectShowPlayer::StepForward()
{
	if (!_isCreated)
		return -1;

	if (_playerType != PLAYERTYPE_WINDOWS_MEDIA_FILE)
		return -1;

	CComQIPtr<IMediaSeeking> mediaSeeking(_graphBuilder);
	if (mediaSeeking == NULL)
		return -1;

	LONGLONG current;
	HRESULT hr = mediaSeeking->GetCurrentPosition(&current);
	if (hr != S_OK)
		return -1;

	current += 50 * UNIT;
	static LONGLONG stopPos = 3000 * UNIT;
	stopPos += 50 * UNIT;

	bool success = SUCCEEDED(mediaSeeking->SetPositions(
								NULL, AM_SEEKING_NoPositioning,
								//&current, AM_SEEKING_RelativePositioning,
								//&current, AM_SEEKING_AbsolutePositioning, 
								&stopPos, AM_SEEKING_AbsolutePositioning ));

	Start();


	//_h264DecodeFilter->StepForward();

	return 0;
}

int DirectShowPlayer::StepBack()
{
	if (!_isCreated)
		return -1;

	if (_playerType != PLAYERTYPE_WINDOWS_MEDIA_FILE)
		return -1;

	CComQIPtr<IMediaSeeking> mediaSeeking(_graphBuilder);
	if (mediaSeeking == NULL)
		return -1;

	LONGLONG current;
	//HRESULT hr = mediaSeeking->GetCurrentPosition(&current);
	//if (hr != S_OK)
	//	return -1;

	current = -50 * UNIT;
	LONGLONG stopPos = 0;

	bool success = SUCCEEDED(mediaSeeking->SetPositions(
		&current, AM_SEEKING_RelativePositioning | AM_SEEKING_SeekToKeyFrame, 
		&stopPos, AM_SEEKING_IncrementalPositioning ));

	return 0;
}

#ifdef SUPPORT_H264
bool DirectShowPlayer::RenderAllPin()
{
	if (_fileSourceFilter == NULL || _h264DecodeFilter.get() == NULL)
		return false;

	CComPtr<IEnumPins> enumPins;
	if (FAILED(_fileSourceFilter->EnumPins(&enumPins)))
		return false;

	bool isH264Rendered = false;
	CComPtr<IPin> pin;
	while(enumPins->Next(1, &pin, 0) == S_OK)
	{
		PIN_DIRECTION pinDir;
		pin->QueryDirection(&pinDir);

		if (PINDIR_OUTPUT == pinDir && 
			SUCCEEDED(_graphBuilder->Render(pin)) && 
			_h264DecodeFilter->IsConnected())
		{
			isH264Rendered = true;
		}

		pin.Release();
	}

	return isH264Rendered;
}
#endif

#define CHECK_POINTER(p) if ((p) == NULL) { ReleaseAll(); return -2;}
#define CHECK_RESULT(hr) if (FAILED(hr)) { ReleaseAll(); return -3;}

int DirectShowPlayer::InitializePlayer()
{
	if (_isCreated)
		return -1;
	
	if (_playerType == PLAYERTYPE_WINDOWS_MEDIA_FILE)
	{
		_graphBuilder.CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER);
		CHECK_POINTER(_graphBuilder);

#if 0
		_vmr9.CoCreateInstance(CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER);
		_vmr9.CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER);
#endif
		_vmr9.CoCreateInstance(CLSID_VideoRendererDefault, NULL, CLSCTX_INPROC_SERVER);
		CHECK_POINTER(_vmr9);

		CComQIPtr< IVMRFilterConfig > vmrConfig(_vmr9);
		if (vmrConfig != NULL)
		{
			vmrConfig->SetRenderingMode(VMRMode_Windowless);
		}
		else
		{
			CComQIPtr< IVMRFilterConfig9 > vmrConfig9(_vmr9);
			if (vmrConfig9 != NULL)
				vmrConfig9->SetRenderingMode(VMR9Mode_Windowless);
		}

		CHECK_RESULT(_graphBuilder->AddFilter(_vmr9, L"Video Renderer(VMR9)"));

		CComQIPtr<IMediaFilter> filter(_graphBuilder);
		if (filter != NULL)
		{
			filter->SetSyncSource(&_clock);
		}
	}

	HRESULT hr;

	switch (_playerType)
	{
#ifdef SUPPORT_H264
	case PLAYERTYPE_WINDOWS_MEDIA_FILE:
		{
			_h264DecodeFilter = auto_ptr<H264DecodeFilter>(new H264DecodeFilter(NULL, NULL, &hr));
			CHECK_POINTER(_h264DecodeFilter.get());
			CHECK_RESULT(_graphBuilder->AddFilter(_h264DecodeFilter.get(), L"Coship H264 Decoder"));

			string ext = _sourceName.substr(_sourceName.length() - 4);
			ext[1] = tolower(ext[1]);
			ext[2] = tolower(ext[2]);
			ext[3] = tolower(ext[3]);

			WCHAR wcharName[512];
			MultiByteToWideChar(CP_ACP, 0, _sourceName.c_str(), -1, wcharName, 512);

			if (ext == ".asf")
			{
				_fileSourceFilter.CoCreateInstance(CLSID_WMAsfReader, NULL, CLSCTX_INPROC_SERVER);
				CHECK_POINTER(_fileSourceFilter);
				CHECK_RESULT(_graphBuilder->AddFilter(_fileSourceFilter, L"WM ASF Reader"));

				CComQIPtr<IFileSourceFilter> fileSource(_fileSourceFilter);
				hr = fileSource->Load(wcharName, NULL);
				if (FAILED(hr))
				{
					CHECK_RESULT(_graphBuilder->RenderFile(wcharName, NULL));
					if (!_h264DecodeFilter->IsConnected())
					{
						ReleaseAll();
						return -3;
					}
				}
				else if (!RenderAllPin())
				{
					ReleaseAll();
					return -3;
				}
			}
			else
			{
				CHECK_RESULT(_graphBuilder->RenderFile(wcharName, NULL));
				if (!_h264DecodeFilter->IsConnected())
				{
					ReleaseAll();
					return -3;
				}
			}


		}

		break;

	case PLAYERTYPE_H264_FILE_STREAM:
	case PLAYERTYPE_H264_BIT_STREAM:
#endif
	case PLAYERTYPE_RAW_FRAME_STREAM:
		_h264Play = auto_ptr<DDrawH264Play>(new DDrawH264Play(_fps, _width, _height, (_playerType == PLAYERTYPE_RAW_FRAME_STREAM), false));
		CHECK_POINTER(_h264Play.get());
#ifdef SUPPORT_H264
		if (_playerType == PLAYERTYPE_H264_FILE_STREAM)
			_h264Play->SetSourceName(_sourceName.c_str());
		else 
#endif
			_h264Play->SetDataProvider(m_session, _dataProvider, _param);

		break;

	default:
		ReleaseAll();
		return -3;
	}

	_isCreated = true;

	UpdateOutputPosition();

	return 0;
}

void DirectShowPlayer::DestroyPlayer()
{
	if (!_isCreated)
		return;

	CComQIPtr<IVideoWindow> videoWindow(_graphBuilder);
	if (videoWindow != NULL)
	{
		videoWindow->put_MessageDrain((OAHWND) NULL);
		videoWindow.Release();
	}

	ReleaseAll();
}

void DirectShowPlayer::ReleaseAll()
{
	Stop();

#ifdef SUPPORT_H264
	if (_h264DecodeFilter.get() != NULL)
		_graphBuilder->RemoveFilter(_h264DecodeFilter.get());
#endif

	_vmr9.Release();	
	_fileSourceFilter.Release();
	_graphBuilder.Release();
	_h264Play.reset();
#ifdef SUPPORT_H264
	_h264DecodeFilter.reset();
#endif
}